package com.woniu.zsd.permission.aspect;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.woniu.commons.util.JwtUtil;
import com.woniu.zsd.commons.exception.ZsdException;
import com.woniu.zsd.permission.Permission.Permission;
import com.woniu.zsd.permission.mapper.RolesMapper;
import com.woniu.zsd.permission.mapper.RolesResourceMapper;
import io.jsonwebtoken.Claims;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.data.redis.core.RedisTemplate;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.fasterxml.jackson.core.type.TypeReference;


@Aspect
@Component
public class PermissionControlAspect {

    @Autowired
    private RolesMapper rolesMapper;

    @Autowired
    private RolesResourceMapper rolesResourceMapper;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @PostConstruct
    public void init() {
        // 在应用启动时查询角色资源并存入 Redis
        List<Map<String, Object>> allRolesResources = rolesResourceMapper.selectRolesResourceWithDetails();
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String allRolesResourcesJson = objectMapper.writeValueAsString(allRolesResources);
            redisTemplate.opsForValue().set("role:resources:all", allRolesResourcesJson);

            // 按角色名分组资源
            Map<String, List<Map<String, Object>>> groupedRolesResources = allRolesResources.stream()
                    .collect(Collectors.groupingBy(roleResource -> (String) roleResource.get("roleName")));

            // 分别为每种角色缓存其所有资源
            groupedRolesResources.forEach((roleName, roleResources) -> {
                if ("super_admin".equals(roleName) || "t_admin".equals(roleName) || "admin".equals(roleName)) {
                    String key = "role:resources:" + roleName;
                    String roleResourcesJson = null;
                    try {
                        roleResourcesJson = objectMapper.writeValueAsString(roleResources);
                        System.out.println("系统启动时自动加载角色资源"+roleResourcesJson);
                    } catch (JsonProcessingException e) {
                        throw new RuntimeException(e);
                    }
                    redisTemplate.opsForValue().set(key, roleResourcesJson);
                } else if ("user".equals(roleName)) {
                    // 为 user 角色缓存空权限
                    String key = "role:resources:user";
                    redisTemplate.opsForValue().set(key, "[]"); // 缓存空列表
                }
            });
        } catch (Exception e) {
            throw new RuntimeException("初始化角色资源缓存失败", e);
        }
    }

    @Around("@annotation(permission)")
    public Object control(ProceedingJoinPoint joinPoint, Permission permission) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String token = request.getHeader("Token");
        if (!StringUtils.hasLength(token)) {
            throw new ZsdException("未认证", 401);
        }

        Claims claims;
        try {
            claims = jwtUtil.parseToken(token);
        } catch (Exception e) {
            throw new ZsdException("未认证", 401);
        }

        Integer adminId = (Integer) claims.get("id");

        // 获取注解中的资源名
        String resource = permission.value();

        // 查询用户的角色
        String role = rolesMapper.findRoleNameByAdminId(adminId);


        // 从Redis中获取角色资源关联关系  Map<roleName, List<resourceName>>
        List<Map<String, Object>> rolesResources;
        System.out.println(redisTemplate.opsForValue().get("role:resources:" + role));
        String rolesResourcesJson = (String) redisTemplate.opsForValue().get("role:resources:" + role);
        System.out.println("rolesResourcesJson:"+rolesResourcesJson);
        if (rolesResourcesJson == null) {
            // 如果Redis中没有缓存，则从数据库查询并存入Redis
            rolesResources = rolesResourceMapper.selectRolesResourceWithDetails();
            ObjectMapper objectMapper = new ObjectMapper();
            rolesResourcesJson = objectMapper.writeValueAsString(rolesResources);
            redisTemplate.opsForValue().set("role:resources:" + role, rolesResourcesJson);
        } else {
            // 从Redis中获取数据并反序列化为List
            ObjectMapper objectMapper = new ObjectMapper();
            rolesResources = objectMapper.readValue(rolesResourcesJson, new TypeReference<List<Map<String, Object>>>() {});
            System.out.println("rolesResources:"+rolesResources);
        }

        boolean hasPermission = rolesResources.stream()
                .anyMatch(roleResource -> role.equals(roleResource.get("roleName")) && resource.equals(roleResource.get("resourceName")));

        if (!hasPermission) {
            throw new ZsdException("权限不足", 402);
        }

        return joinPoint.proceed();
    }
}
